#include "scanner.h"
#include "md5.h"
#include "utils.h"
#include <iostream>
#include <chrono>
#include <algorithm>
#include <iomanip>
#include <dirent.h>
#include <sys/stat.h>
#include <cstring>
#include <unistd.h>

namespace FileScanner {

Scanner::Scanner(const std::string& directory,
                long long minSize,
                int workerCount,
                Database& db)
    : directory_(directory), minSize_(minSize), workerCount_(workerCount), db_(db),
      processedCount_(0), totalCount_(0), newFilesCount_(0), skippedCount_(0),
      scanning_(true), filesCollected_(false) {
}

void Scanner::scan() {
    std::cout << "扫描目录: \"" << directory_ << "\"" << std::endl;
    std::cout << "最小文件大小: " << minSize_ << " 字节" << std::endl;
    std::cout << "工作线程数: " << workerCount_ << std::endl;

    // 预加载数据库中的文件路径
    db_.preloadFilePaths();

    // 收集所有需要处理的文件
    collectFiles();

    if (totalCount_ == 0) {
        return;
    }

    std::cout << "找到符合条件的文件: " << totalCount_.load() << " 个" << std::endl;

    // 启动工作线程
    std::vector<std::thread> workers;
    for (int i = 0; i < workerCount_; ++i) {
        workers.emplace_back(&Scanner::workerThread, this);
    }

    // 等待所有工作线程完成
    for (auto& worker : workers) {
        worker.join();
    }

    // 停止扫描
    scanning_ = false;

    // 不输出详细统计信息，保持与Rust版本一致
}

// 检查文件是否为普通文件
static bool isRegularFile(const std::string& path) {
    struct stat st;
    if (stat(path.c_str(), &st) != 0) {
        return false;
    }
    return S_ISREG(st.st_mode);
}

// 获取文件大小
static long long getFileSize(const std::string& path) {
    struct stat st;
    if (stat(path.c_str(), &st) != 0) {
        return -1;
    }
    return static_cast<long long>(st.st_size);
}

// 检查目录是否存在
static bool directoryExists(const std::string& path) {
    struct stat st;
    if (stat(path.c_str(), &st) != 0) {
        return false;
    }
    return S_ISDIR(st.st_mode);
}

// 递归收集文件
static void collectFilesRecursive(const std::string& dirPath, long long minSize,
                                 std::queue<std::string>& fileQueue,
                                 std::atomic<long long>& totalCount,
                                 std::mutex& queueMutex) {
    DIR* dir = opendir(dirPath.c_str());
    if (!dir) {
        return;
    }

    struct dirent* entry;
    while ((entry = readdir(dir)) != nullptr) {
        // 跳过 . 和 ..
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        std::string fullPath = joinPath(dirPath, entry->d_name);

        if (entry->d_type == DT_DIR) {
            // 递归处理子目录
            collectFilesRecursive(fullPath, minSize, fileQueue, totalCount, queueMutex);
        } else if (entry->d_type == DT_REG || (entry->d_type == DT_UNKNOWN && isRegularFile(fullPath))) {
            // 处理普通文件
            long long fileSize = getFileSize(fullPath);
            if (fileSize >= minSize) {
                std::lock_guard<std::mutex> lock(queueMutex);
                fileQueue.push(fullPath);
                totalCount++;
            }
        }
    }

    closedir(dir);
}

void Scanner::collectFiles() {
    if (!directoryExists(directory_)) {
        logError("目录不存在: " + directory_);
        return;
    }

    try {
        collectFilesRecursive(directory_, minSize_, fileQueue_, totalCount_, queueMutex_);
    } catch (const std::exception& e) {
        logError("文件系统错误: " + std::string(e.what()));
    }

    // 标记文件收集完成
    filesCollected_ = true;
    queueCondition_.notify_all();
}

void Scanner::workerThread() {
    while (true) {
        std::string filePath;

        {
            std::unique_lock<std::mutex> lock(queueMutex_);
            queueCondition_.wait(lock, [this] {
                return !fileQueue_.empty() || (filesCollected_ && fileQueue_.empty());
            });

            // 如果队列为空且文件收集完成，退出线程
            if (fileQueue_.empty() && filesCollected_) {
                break;
            }

            // 如果队列为空但文件还没收集完成，继续等待
            if (fileQueue_.empty()) {
                continue;
            }

            filePath = fileQueue_.front();
            fileQueue_.pop();
        }

        processFile(filePath);
    }
}

void Scanner::processFile(const std::string& filePath) {
    try {
        // 原子递增并获取当前处理序号
        long long current = ++processedCount_;
        long long total = totalCount_;

        long long fileSize = getFileSize(filePath);
        if (fileSize < 0) {
            logError("获取文件大小失败: " + filePath);
            return;
        }

        // 检查文件是否已存在于数据库中
        if (db_.hasFile(filePath, fileSize)) {
            // 输出处理进度和文件路径（带Skip标记）
            std::cout << "[" << current << "/" << total << "] [Skip] " << filePath << std::endl;
            skippedCount_++;
            return;
        }

        // 计算 MD5
        std::string md5 = calculateMD5(filePath);
        if (md5.empty()) {
            // MD5计算失败时也输出Skip标记，保持与Rust版本一致
            std::cout << "[" << current << "/" << total << "] [Skip] " << filePath << std::endl;
            return;
        }

        // 插入数据库
        if (db_.insertFile(filePath, md5, fileSize)) {
            newFilesCount_++;
            // 输出处理进度和文件路径
            std::cout << "[" << current << "/" << total << "] " << filePath << std::endl;
        } else {
            std::cerr << "保存文件记录失败: " << filePath << std::endl;
        }

    } catch (const std::exception& e) {
        logError("处理文件时出错: " + filePath + " - " + e.what());
    }
}

void Scanner::checkIntegrity() {
    auto files = db_.getAllFiles();
    long long totalFiles = files.size();
    long long checkedFiles = 0;
    long long removedFiles = 0;

    std::cout << "数据库中共有 " << totalFiles << " 个文件记录" << std::endl;

    if (totalFiles == 0) {
        return;
    }

    for (const auto& file : files) {
        checkedFiles++;

        std::string prefix;
        bool shouldRemove = false;

        if (!isRegularFile(file.path)) {
            // 文件不存在，从数据库中删除
            shouldRemove = true;
            prefix = "D";
        } else {
            // 检查文件大小是否匹配
            long long currentSize = getFileSize(file.path);
            if (currentSize < 0 || currentSize != file.size) {
                // 文件大小不匹配，从数据库中删除
                shouldRemove = true;
                prefix = "D";
            } else {
                prefix = "N";
            }
        }

        // 输出检查结果：[D或者N] [当前文件序号/总文件数目] 当前文件绝对路径
        std::cout << "[" << prefix << "] [" << checkedFiles << "/" << totalFiles << "] "
                  << file.path << std::endl;

        if (shouldRemove) {
            if (db_.removeFile(file.path)) {
                removedFiles++;
            } else {
                std::cerr << "删除文件记录失败: " << file.path << std::endl;
            }
        }
    }
}

} // namespace FileScanner
